package com.wzcl.app.service.impl;

import com.wzcl.app.dao.model.KnowledgePoint;
import com.wzcl.app.dao.model.Topic;
import com.wzcl.app.dao.model.TopicAndKnowledgePoint;
import com.wzcl.app.dao.model.WrongTopic;
import com.wzcl.app.dao.repository.WrongTopicRepository;
import com.wzcl.app.model.common.MyPage;
import com.wzcl.app.model.dto.KnowledgePointDto;
import com.wzcl.app.model.dto.WrongTopicDto;
import com.wzcl.app.model.vo.TopicVo;
import com.wzcl.app.model.vo.WrongTopicPreviewVo;
import com.wzcl.app.model.vo.WrongTopicVo;
import com.wzcl.app.service.TopicAndKnowledgePointService;
import com.wzcl.app.service.TopicService;
import com.wzcl.app.service.WrongTopicService;
import com.wzcl.app.utils.NativeResultProcessUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.Tuple;
import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Log4j2
@Service
@Transactional
public class WrongTopicServiceImpl implements WrongTopicService {

    @Autowired
    private WrongTopicRepository repository;

    @Autowired
    private TopicAndKnowledgePointService topicAndKnowledgePointService;

    @Autowired
    private TopicService topicService;

    @Override
    public void addWrongTopic(WrongTopicDto wrongTopicDto) {
        Topic topic = topicService.getAndCheckById(wrongTopicDto.getTopicId());
        List<WrongTopic> list = findAllBYUserPhoneAndTopic(wrongTopicDto);
        //获取该题的知识点
        List<TopicAndKnowledgePoint> knowledgePointList = topicAndKnowledgePointService.findTopicAndKnowledgePointByTopic(topic);
        //如果存在则修改用户答案,不存在则添加
        if(list.isEmpty()){
            for (TopicAndKnowledgePoint topicAndKnowledgePoint : knowledgePointList) {
                WrongTopic wrongTopic = new WrongTopic();
                wrongTopic.setUserPhone(wrongTopicDto.getUserPhone());
                wrongTopic.setUserAnswer(wrongTopicDto.getUserAnswer());
                wrongTopic.setTopicAndKnowledgePoint(topicAndKnowledgePoint);
                list.add(wrongTopic);
            }
            if(list.size() >0 ){
                repository.saveAll(list);
            }
        }else{
            Date createTime = list.get(0).getCreateTime();
            //之前有错题（同步一下知识点）
            for (WrongTopic wrongTopic : list) {
                for (int i = 0; i < knowledgePointList.size(); i++) {
                    //找到对应错题记录
                    if(wrongTopic.getTopicAndKnowledgePoint().getId().equals(knowledgePointList.get(i).getId())){
                        wrongTopic.setUserAnswer(wrongTopicDto.getUserAnswer());
                        //处理过的知识点移除掉
                        knowledgePointList.remove(i);
                        break;
                    }
                }
            }
            //还有没有记录的知识点
            if(knowledgePointList.size()>0){
                for (TopicAndKnowledgePoint topicAndKnowledgePoint : knowledgePointList) {
                    WrongTopic wrongTopic = new WrongTopic();
                    wrongTopic.setUserPhone(wrongTopicDto.getUserPhone());
                    wrongTopic.setUserAnswer(wrongTopicDto.getUserAnswer());
                    wrongTopic.setCreateTime(createTime);
                    wrongTopic.setTopicAndKnowledgePoint(topicAndKnowledgePoint);
                    list.add(wrongTopic);
                }
            }
            repository.saveAll(list);
        }
    }

    @Override
    public void delWrongTopicByTopicIdAndUserPhone(Integer KnowledgePointId, String userPhone){
        repository.delByTopicIdAndUserPhone(KnowledgePointId,userPhone);
    }

    @Override
    public void delWrongTopicByTopicId(Integer topicId) {
        repository.delByTopicId(topicId);
    }

    @Override
    public void delWrongTopicByKnowledgePointId(Integer KnowledgePointId) {
        repository.delByKnowledgePointId(KnowledgePointId);
    }

    @Override
    public void delWrongTopicByTopicAndKnowledgePointId(Integer knowledgePointId) {
        repository.delByTopicAndKnowledgePointId(knowledgePointId);
    }

    @Override
    public Long countWrongTopicGroupByTopic(WrongTopicDto wrongTopicDto) {
        wrongTopicDto.setGroupName("topicAndKnowledgePoint.topic.id");
        return  repository.count(getSpecification(wrongTopicDto));
    }

    @Override
    public Long countWrongTopicGroupByKnowledgePoint(WrongTopicDto wrongTopicDto) {
        wrongTopicDto.setGroupName("topicAndKnowledgePoint.knowledgePoint.id");
        return repository.count(getSpecification(wrongTopicDto));
    }

    @Override
    public List<WrongTopicPreviewVo> findCondition(WrongTopicDto wrongTopicDto) {
        String userPhone = wrongTopicDto.getUserPhone();
        Integer subjectId = null;
        Integer gradeId = null;
        KnowledgePointDto knowledgePoint = wrongTopicDto.getKnowledgePoint();
        if(knowledgePoint != null){
             subjectId = knowledgePoint.getSubjectId();
             gradeId = knowledgePoint.getGradeId();
        }
        List<Tuple> result = repository.findCondition(userPhone, subjectId, gradeId);
        if(result   != null && result.size() > 0){
            return result.stream().map(tuple -> NativeResultProcessUtil.processResult(tuple, WrongTopicPreviewVo.class)).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public MyPage<WrongTopicVo> findWrongTopicPage(WrongTopicDto wrongTopicDto) {
        wrongTopicDto.setGroupName("id");
        Page<WrongTopic> page = repository.findAll(getSpecification(wrongTopicDto), wrongTopicDto.getPageable());
        if(page.getContent().size() > 0){
            MyPage<WrongTopicVo> myPage = new MyPage<>();
            myPage.setTotalElements(page.getTotalElements());
            myPage.setPageSize(page.getSize());
            myPage.setPageNumber(page.getNumber());
            myPage.setNumberOfElements(page.getNumberOfElements());
            //转换为需要的错题
            myPage.setContent(page.getContent().stream().map(wrongTopic -> {
                WrongTopicVo wrongTopicVo = new WrongTopicVo();
                wrongTopicVo.setId(wrongTopic.getId());
                wrongTopicVo.setUpdateTime(wrongTopic.getUpdateTime());
                wrongTopicVo.setCreateTime(wrongTopic.getCreateTime());
                wrongTopicVo.setUserAnswer(wrongTopic.getUserPhone());
                wrongTopicVo.setTopic(TopicVo.create(wrongTopic.getTopicAndKnowledgePoint().getTopic()));
                return wrongTopicVo;
            }).collect(Collectors.toList()));
            return myPage;
        }
        return null;
    }

    private List<WrongTopic> findAllBYUserPhoneAndTopic(WrongTopicDto wrongTopicDto){
        List<WrongTopic> list = repository.findAllByUserPhoneAndTopicId(wrongTopicDto.getUserPhone(), wrongTopicDto.getTopicId());
        return list == null?new ArrayList<>():list;
    }

    private Specification<WrongTopic> getSpecification(WrongTopicDto wrongTopicDto){
        return new Specification<WrongTopic>() {
            @Override
            public Predicate toPredicate(Root<WrongTopic> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if(StringUtils.isNotBlank(wrongTopicDto.getUserPhone())){
                    predicates.add(criteriaBuilder.equal(root.get("userPhone"),wrongTopicDto.getUserPhone()));
                }
                KnowledgePointDto knowledgePoint = wrongTopicDto.getKnowledgePoint();
                if(knowledgePoint !=null){
                    Join<WrongTopic, TopicAndKnowledgePoint> topicAndKnowledgePointPath = root.join("topicAndKnowledgePoint");
                    Join<TopicAndKnowledgePoint, KnowledgePoint> knowledgePointPath = topicAndKnowledgePointPath.join("knowledgePoint");
                    if(knowledgePoint.getId() != null){
                        predicates.add(criteriaBuilder.equal(knowledgePointPath.get("id"),knowledgePoint.getId()));
                    }
                    if(knowledgePoint.getGradeId() != null){
                        predicates.add(criteriaBuilder.equal(knowledgePointPath.get("gradeId"),knowledgePoint.getGradeId()));
                    }
                    if(knowledgePoint.getSubjectId() != null){
                        predicates.add(criteriaBuilder.equal(knowledgePointPath.get("subjectId"),knowledgePoint.getSubjectId()));
                    }
                    if(StringUtils.isNotBlank(knowledgePoint.getChapter())){
                        predicates.add(criteriaBuilder.equal(knowledgePointPath.get("chapter"),knowledgePoint.getChapter()));
                    }
                    if(StringUtils.isNotBlank(knowledgePoint.getPoint())){
                        predicates.add(criteriaBuilder.equal(knowledgePointPath.get("point"),knowledgePoint.getPoint()));
                    }
                }
                Path group = wrongTopicDto.getGroupName(root);
                if(group != null){
                    criteriaQuery.groupBy(group);
                }
                return criteriaQuery.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
            }
        };
    }
}
